#ifndef _MHWGeometry
#define _MHWGeometry
//
//-
// ==========================================================================
// Copyright (C) 2010 Autodesk, Inc., and/or its licensors.  All rights
// reserved.
//
// The coded instructions, statements, computer programs, and/or related
// material (collectively the "Data") in these files contain unpublished
// information proprietary to Autodesk, Inc. ("Autodesk") and/or its
// licensors,  which is protected by U.S. and Canadian federal copyright law
// and by international treaties.
//
// The Data may not be disclosed or distributed to third parties or be
// copied or duplicated, in whole or in part, without the prior written
// consent of Autodesk.
//
// The copyright notices in the Software and this entire statement,
// including the above license grant, this restriction and the following
// disclaimer, must be included in all copies of the Software, in whole
// or in part, and all derivative works of the Software, unless such copies
// or derivative works are solely in the form of machine-executable object
// code generated by a source language processor.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
// AUTODESK DOES NOT MAKE AND HEREBY DISCLAIMS ANY EXPRESS OR IMPLIED
// WARRANTIES INCLUDING, BUT NOT LIMITED TO, THE WARRANTIES OF
// NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE,
// OR ARISING FROM A COURSE OF DEALING, USAGE, OR TRADE PRACTICE. IN NO
// EVENT WILL AUTODESK AND/OR ITS LICENSORS BE LIABLE FOR ANY LOST
// REVENUES, DATA, OR PROFITS, OR SPECIAL, DIRECT, INDIRECT, OR
// CONSEQUENTIAL DAMAGES, EVEN IF AUTODESK AND/OR ITS LICENSORS HAS
// BEEN ADVISED OF THE POSSIBILITY OR PROBABILITY OF SUCH DAMAGES.
// ==========================================================================
//+
//
// ****************************************************************************

#if defined __cplusplus


#include <maya/MString.h>
#include <maya/MObject.h>
#include <maya/MColor.h>

class MUserData;

// ****************************************************************************
// NAMESPACE

namespace MHWRender
{

class MVertexBufferDescriptor;
class MVertexBuffer;
class MIndexBuffer;
class MShaderInstance;

// ****************************************************************************
// CLASS DECLARATION (MGeometry)

//! \ingroup OpenMayaRender
//! \brief Class for working with geometric structures used to draw objects
/*!
This class provides a means to specify and access geometric data used to draw
objects in Viewport 2.0.

Objects of type MGeometry cannot be created or destroyed. They are only
accessed through methods on draw override classes such as MPxShaderOverride
or MPxGeometryOverride.

Each MGeometry object contains zero or more vertex buffers and zero or more
index buffers. In read-only scenarios, these buffers describe geometry that
is about to be drawn and can be used to bind custom shaders to the actual
geometry streams on the GPU (see MPxShaderOverride for more details). In the
non-read only scenario, MGeometry can be used to provide vertex and index data
to Maya to use to draw Maya DAG objects with arbitrary shaders (see
MPxGeometryOverride). In all cases the MGeometry instance owns the vertex and
index buffers and manages their lifetimes.
*/
class OPENMAYARENDER_EXPORT MGeometry
{
public:

	//! Specifies data types to use with buffers
	enum DataType {
		//! Invalid element type (default value)
		kInvalidType,
		//! IEEE single precision floating point
		kFloat,
		//! IEEE double precision floating point
		kDouble,
		//! Signed char
		kChar,
		//! Unsigned char
		kUnsignedChar,
		//! Signed 16-bit integer
		kInt16,
		//! Unsigned 16-bit integer
		kUnsignedInt16,
		//! Signed 32-bit integer
		kInt32,
		//! Unsigned 32-bit integer
		kUnsignedInt32
	};
	static const MString& dataTypeString(MGeometry::DataType d);

	//! Specifies the semantic of a data buffer
	enum Semantic {
		//! Invalid data type (default value)
		kInvalidSemantic,
		//! Position vector
		kPosition,
		//! Normal vector
		kNormal,
		//! Texture coordinate tuple
		kTexture,
		//! Color tuple
		kColor,
		//! Tangent vector
		kTangent,
		//! Bi-normal vector
		kBitangent,
	};
	static const MString& semanticString(MGeometry::Semantic s);

	//! Specifies the data primitive type constructed by the indexing array
	enum Primitive
	{
		//! Default value is not valid
		kInvalidPrimitive,
		//! Corresponds to GL_POINTS in OpenGL
		kPoints,
		//! Corresponds to GL_LINES in OpenGL
		kLines,
		//! Corresponds to GL_LINE_STRIP in OpenGL
		kLineStrip,
		//! Corresponds to GL_TRIANGLES In OpenGL
		kTriangles,
		//! Corresponds to GL_TRIANGLE_STRIP in OpenGL
		kTriangleStrip,
	};
	static const MString& primitiveString(MGeometry::Primitive p);

	//! Specifies draw mode for render items
	enum DrawMode
	{
		//! Draw in all modes
		kAll,
		//! Draw in wireframe mode only
		kWireframe,
		//! Draw in shaded mode only
		kShaded,
	};
	static const MString& drawModeString(MGeometry::DrawMode d);

	int vertexBufferCount() const;
	const MVertexBuffer* vertexBuffer(int index) const;
	MVertexBuffer* vertexBuffer(int index);
	MVertexBuffer* createVertexBuffer(const MVertexBufferDescriptor& desc);
	bool deleteVertexBuffer(int index);

	int indexBufferCount() const;
	const MIndexBuffer* indexBuffer(int index) const;
	MIndexBuffer* indexBuffer(int index);
	MIndexBuffer* createIndexBuffer(MGeometry::DataType type);
	bool deleteIndexBuffer(int index);

	static const char* className();

private:
	MGeometry();
	MGeometry(const MGeometry&) {}
	MGeometry& operator=(const MGeometry&) { return *this; }
	~MGeometry();

	void* fVertexData;
	void* fIndexData;

	friend class MRenderItem;
};


// ****************************************************************************
// CLASS DECLARATION (MVertexBufferDescriptor)
//! \ingroup OpenMayaRender
//! \brief Describes properties of a vertex buffer
/*!
This class gives a complete description of a vertex buffer and is used by
MGeometry, MVertexBuffer and MGeometryRequirements to simplify management of
vertex buffer attributes.

Note that not all combinations of semantics, data types and dimensions are
currently supported. Attempts to create vertex buffers with unsupported
attributes will fail.
*/
class OPENMAYARENDER_EXPORT MVertexBufferDescriptor
{
public:
	MVertexBufferDescriptor();
	MVertexBufferDescriptor(
		const MString& name,
		MGeometry::Semantic semantic,
		MGeometry::DataType dataType,
		int dimension);
	~MVertexBufferDescriptor();

BEGIN_NO_SCRIPT_SUPPORT:
	//! NO SCRIPT SUPPORT
	MVertexBufferDescriptor(const MVertexBufferDescriptor& other);
	//! NO SCRIPT SUPPORT
	MVertexBufferDescriptor& operator=(const MVertexBufferDescriptor& other);
END_NO_SCRIPT_SUPPORT:

	MString name() const;
	void setName(const MString& n);

	MGeometry::Semantic semantic() const;
	void setSemantic(MGeometry::Semantic s);

	MGeometry::DataType dataType() const;
	void setDataType(MGeometry::DataType d);
	unsigned int dataTypeSize() const;

	int dimension() const;
	void setDimension(int d);

	int offset() const;
	int stride() const;

	static const char* className();

private:
	MString fName;
	MGeometry::Semantic fSemantic;
	MGeometry::DataType fDataType;
	int fDimension;
	int fOffset;
	int fStride;

	friend class MRenderItem;
};


// ****************************************************************************
// CLASS DECLARATION (MVertexBufferDescriptorList)
//! \ingroup OpenMayaRender
//! \brief A list of MVertexBufferDescriptor objects
/*!
A list of MVertexBufferDescriptor objects.
*/
class OPENMAYARENDER_EXPORT MVertexBufferDescriptorList
{
public:
	MVertexBufferDescriptorList();
	~MVertexBufferDescriptorList();

	int	length() const;
	bool getDescriptor(int index, MVertexBufferDescriptor& desc) const;

	bool append(const MVertexBufferDescriptor& desc);
	bool removeAt(int index);
	void clear();

	static const char* className();

private:
	MVertexBufferDescriptorList(const MVertexBufferDescriptorList&) {}
	MVertexBufferDescriptorList& operator=(const MVertexBufferDescriptorList&) { return *this; }

	void* fData;
};


// ****************************************************************************
// CLASS DECLARATION (MVertexBuffer)
//! \ingroup OpenMayaRender
//! \brief Vertex buffer for use with MGeometry
/*!
This class represents a vertex buffer with attributes described by the
descriptor member.

When retrieving a vertex buffer for binding to custom shaders
(MPxShaderOverride), resourceHandle() may be called to get the device dependent
handle to the vertex buffer on the GPU.

When creating a vertex buffer to supply geometric data to Maya
(MPxGeometryOverride), acquire() may be called to get a pointer to a block of
memory to fill with said data. Once filled, commit() must be called to apply
the data to the buffer.
*/
class OPENMAYARENDER_EXPORT MVertexBuffer
{
public:
	const MVertexBufferDescriptor& descriptor() const;
	void* resourceHandle() const;

	void* acquire(unsigned int size);
	void commit(void* buffer);

	static const char* className();

private:
	MVertexBuffer(const MVertexBufferDescriptor& descriptor);
	MVertexBuffer(const MVertexBuffer&) {}
	MVertexBuffer& operator=(const MVertexBuffer&) { return *this; }
	~MVertexBuffer();

	MVertexBufferDescriptor fDescriptor;
	unsigned int fSize;
	char* fData;
	char* fFinalData;
	void* fHwResource;

	friend class MGeometry;
	friend class MRenderItem;
};


// ****************************************************************************
// CLASS DECLARATION (MIndexBuffer)
//! \ingroup OpenMayaRender
//! \brief Index buffer for use with MGeometry
/*!
This class represents an index buffer with a specific data type.

When retrieving an index buffer for binding to custom shaders
(MPxShaderOverride), resourceHandle() may be called to get the device dependent
handle to the index buffer on the GPU.

When creating an index buffer to supply geometric data to Maya
(MPxGeometryOverride), acquire() may be called to get a pointer to a block of
memory to fill with said data. Once filled, commit() must be called to apply
the data to the buffer.
*/
class OPENMAYARENDER_EXPORT MIndexBuffer
{
public:
	MGeometry::DataType dataType() const;
	unsigned int size() const;
	void* resourceHandle() const;

	void* acquire(unsigned int size);
	void commit(void* buffer);

	static const char* className();

private:
	MIndexBuffer(MGeometry::DataType type);
	MIndexBuffer(const MIndexBuffer&) {}
	MIndexBuffer& operator=(const MIndexBuffer&) { return *this; }
	~MIndexBuffer();

	MGeometry::DataType fDataType;
	unsigned int fSize;
	char* fData;
	char* fFinalData;
	void* fHwResource;

	friend class MGeometry;
	friend class MRenderItem;
};


// ****************************************************************************
// CLASS DECLARATION (MRenderItem)
//! \ingroup OpenMayaRender
//! \brief A single renderable entity
/*!
MRenderItem represents a single renderable entity. Each such entity is defined
by a name, a primitive type and a draw mode.

A list of MRenderItem objects is passed to the draw method of implementations
of MPxShaderOverride to indicate the objects that should be drawn immediately
by the override. If the implementation wishes to manually bind data streams it
can call MRenderItem::geometry() to access the vertex buffers and index buffers
that have already been generate for the render item.

MRenderItem objects are used by implementations of MPxGeometryOverride for two
purposes. First, MPxGeometryOverride::updateRenderItems() can create and add new
render items to the list of items that will be drawn for a specific instance
of a DAG object. This method can also enable/disable render items in the list
and set a custom solid color shader on any user defined items. Later, a list
of render items is provided to MPxGeometryOverride::populateGeometry(), to
indicate index buffers that need to be generated. This list contains both the
automatically generated render items Maya creates for shader assignments as
well as the render items created in MPxGeometryOverride::updateRenderItems().
*/
class OPENMAYARENDER_EXPORT MRenderItem
{
public:
	MRenderItem(
		const MString& name,
		MGeometry::Primitive primitive,
		MGeometry::DrawMode mode,
		bool raiseAboveShaded);
	~MRenderItem();

	bool setShader(
		const MShaderInstance* shader,
		const MString* customStreamName=NULL);
	void setCustomData(MUserData* userData);
	void enable(bool on);

	bool associateWithIndexBuffer(const MIndexBuffer* buffer) const;
	MUserData* customData() const;
	bool isEnabled() const;
	MString name() const;
	MGeometry::Primitive primitive() const;
	MGeometry::DrawMode drawMode() const;
	const MVertexBufferDescriptorList& requiredVertexBuffers() const;
	const MGeometry* geometry() const;

	static const char* className();

private:
	MRenderItem();
	MRenderItem(const MRenderItem&) {}
	MRenderItem& operator=(const MRenderItem&) { return *this; }

	void clearGeometryData();

	const void* fData;
	void* fOwnedData;
	const void* fIndexData;
	void* fGeometryData;
	bool fConsolidated;
    void* fDrawContext;
	MVertexBufferDescriptorList fReqDescList;

	static void sMRenderItemPrePostDrawCallback(void* ctx, void* item, bool pre);

	friend class MGeometryRequirements;
	friend class MDrawContext;
};


// ****************************************************************************
// CLASS DECLARATION (MRenderItemList)
//! \ingroup OpenMayaRender
//! \brief A list of MRenderItem objects
/*!
A list of MRenderItem objects. All items in the list are owned by the list.
This class cannot be created or destroyed, it is only passed to the user
through various interfaces.
*/
class OPENMAYARENDER_EXPORT MRenderItemList
{
public:
	int	length() const;
	int indexOf(
		const MString& name,
		MGeometry::Primitive primitive,
		MGeometry::DrawMode mode) const;
	const MRenderItem* itemAt(int index) const;

	MRenderItem* itemAt(int index);
	bool append(MRenderItem* item);
	bool removeAt(int index);
	void clear();

	static const char* className();

private:
	MRenderItemList();
	MRenderItemList(const MRenderItemList&) {}
	MRenderItemList& operator=(const MRenderItemList&) { return *this; }
	~MRenderItemList();

	void* fData;

	friend class MGeometryRequirements;
};


// ****************************************************************************
// CLASS DECLARATION (MGeometryRequirements)
//! \ingroup OpenMayaRender
//! \brief Geometry requirements
/*!
This class is used to describe the geometry requirements to be fulfilled by an
implementation of MPxGeometryOverride. It represents the union of all
requirements from all shaders assigned to the object being evaluated by the
MPxGeometryOverride instance.

There are two parts to the requirements. First, the vertex requirements are
accessed through the requirementDescriptors() method. For each such requirement,
implementations of MPxGeometryOverride should create a vertex buffer on the
MGeometry instance which matchs the vertex buffer descriptor from the
requirement and fill it with data. Second, each item in the render item list
requires an index buffer. The render item defines what type of primitive the
index buffer should reference. For each render item, implementations of
MPxGeometryOverride should create an index buffer on the MGeometry instance and
fill it with data. Then MRenderItem::associateWithIndexBuffer() should be
called on the item.
*/
class OPENMAYARENDER_EXPORT MGeometryRequirements
{
public:
	const MVertexBufferDescriptorList& requirementDescriptors() const;
	const MRenderItemList& renderItemList() const;

	static const char* className();

private:
	MGeometryRequirements();
	~MGeometryRequirements();

	void setIndexData(const void* indexData);

	void* fReqData;
	MVertexBufferDescriptorList fDescList;
	MRenderItemList fItemList;

	friend class MRenderItem;
};

} // namespace MHWRender

// ****************************************************************************

#endif /* __cplusplus */
#endif /* _MHWGeometry */

